package com.sinodata.bsm.center.purview;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;

import com.sino.uam.entity.ObjFunRel;
import com.sino.uam.support.UAMFascade;
import com.sinodata.bsm.center.bean.RelationHelper;
import com.sinodata.bsm.center.bean.ResBean;
import com.sinodata.bsm.center.cache.ResCache;
import com.sinodata.bsm.center.cache.ResViewCache;
import com.sinodata.bsm.center.cache.ResViewRelCache;
import com.sinodata.bsm.center.cache.TopuCatalogCache;
import com.sinodata.bsm.center.cache.TopuConfCache;
import com.sinodata.bsm.center.service.performance.RealTimeService;
import com.sinodata.bsm.center.user.UserUtil;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.center.util.system.SystemContext;
import com.sinodata.bsm.center.util.web.Struts2Utils;
import com.sinodata.bsm.common.vo.RealTimeViewConf;
import com.sinodata.bsm.common.vo.Res;
import com.sinodata.bsm.common.vo.ResView;
import com.sinodata.bsm.common.vo.ResViewRel;
import com.sinodata.bsm.common.vo.TopuCatalog;
import com.sinodata.bsm.common.vo.TopuConf;

/**
 * 
 * <p>
 * Description: 用户权限判断类
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-8-7 PM 5:23:45      liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class UserFunctionValidate {

    private static ResViewCache resViewCache = SpringContextHolder.getBean(ResViewCache.class);

    private static ResViewRelCache resViewRelCache = SpringContextHolder.getBean(ResViewRelCache.class);

    private static ResCache resCache = SpringContextHolder.getBean(ResCache.class);

    private static TopuConfCache topuConfCache = SpringContextHolder.getBean(TopuConfCache.class);

    private static TopuCatalogCache topuCatalogCache = SpringContextHolder.getBean(TopuCatalogCache.class);

    /**
     * 判断系统功能是否有权限
     * 
     * @param functionName
     * @return
     */
    public static boolean sysFunctionValidate(String functionName) {
        String userId = UserUtil.getInstance().getCurrentUserId();
        return sysFunctionValidate(userId, functionName, Struts2Utils.getRequest().getSession());
    }

    /**
     * 判断系统功能是否有权限
     * 
     * @param userId
     * @param functionName
     * @param session
     * @return
     */
    private static boolean sysFunctionValidate(String userId, String functionName, HttpSession session) {
        if (UserUtil.getInstance().isSysAdmin(userId)) {
            return true;
        }
        if (UserUtil.getInstance().isGuest(userId)) { //guest用户有全部数据的查看权限,但没有管理权限
            return false;
        }
        Map<String, Map<String, List<Long>>> map = getUserPurviewMap(userId, session);
        Map<String, List<Long>> temp = map.get(FunctionConstants.TYPE_SYSTEM_FUNCTION);
        List<Long> sys = temp.get(functionName);
        if (sys != null && sys.size() > 0) {
            return true;
        }
        return false;
    }

    /**
     * 判断视图功能是否有权限（视图除了具备资源维护权限设置外还具备视图是否可见功能）
     * 判断视图是够可见传入 FunctionConstants.VIEW_VIEW
     * 判断视图是否可新增资源传入 FunctionConstants.VIEW_ADD_RES
     * 
     * @param functionName
     * @return
     */
    public static boolean viewFunctionValidate(Long viewId, String functionName) {
        String userId = UserUtil.getInstance().getCurrentUserId();
        return viewFunctionValidate(viewId, userId, functionName, Struts2Utils.getRequest().getSession());
    }

    /**
     * 判断视图功能是否有权限（视图除了具备资源维护权限设置外还具备视图是否可见功能）
     * 
     * @param userId
     * @param functionName
     * @param session
     * @return
     */
    private static boolean viewFunctionValidate(Long viewId, String userId, String functionName, HttpSession session) {
        if (UserUtil.getInstance().isSysAdmin(userId)) {
            return true;
        }
        if (UserUtil.getInstance().isGuest(userId)) { //guest用户有全部数据的查看权限
            return true;
        }
        Map<String, Map<String, List<Long>>> map = getUserPurviewMap(userId, session);
        Map<String, List<Long>> temp = map.get(FunctionConstants.TYPE_VIEW_FUNCTION);
        List<Long> view = temp.get(functionName);
        if (view != null && view.size() > 0) {
            if (view.contains(viewId)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否有任何一个视图显示
     * 
     * @return
     */
    public static boolean isViewDisplay() {
        String userId = UserUtil.getInstance().getCurrentUserId();
        if (UserUtil.getInstance().isSysAdmin(userId)) {
            return true;
        }
        if (UserUtil.getInstance().isGuest(userId)) { //guest用户有全部数据的查看权限
            return true;
        }
        ResView[] resViews = resViewCache.findAll();
        if (resViews != null) {
            for (ResView resView : resViews) {
                if (viewFunctionValidate(resView.getId(), userId, FunctionConstants.VIEW_VIEW, Struts2Utils.getRequest().getSession())) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 是否是Guest角色
     * 
     * @return
     */
    public static boolean isGuestRole() {
        String userId = UserUtil.getInstance().getCurrentUserId();
        if (UserUtil.getInstance().isGuest(userId)) {
            return true;
        }
        return false;
    }

    /**
     * 是否具备操作权限 //WhetherOperationAuthority  用于屏蔽菜单使用 (已废弃，使用思路错误)
     * 
     * @return
     */
    //    public static boolean whetherOperAuth() {
    //        String userId = UserUtil.getInstance().getCurrentUserId();
    //        if (UserUtil.getInstance().isSysAdmin(userId)) {
    //            return true;
    //        }
    //        if (UserUtil.getInstance().isGuest(userId)) { //guest用户有全部数据的查看权限
    //            return false;
    //        }
    //        return false;
    //    }
    /**
     * 获取某资源功能是否有权限
     * 
     * @param resId
     * @param functionName
     * @return
     */
    public static boolean resFunctionValidate(Long resId, String functionName) {
        String userId = UserUtil.getInstance().getCurrentUserId();
        return resFunctionValidate(userId, resId, functionName, Struts2Utils.getRequest().getSession());
    }

    /**
     * 根据账号，资源ID和功能名称返回该资源功能是否有权限供外界所调用
     * 资源本身无权限，向上查找父资源是否有权限
     * 
     * @param userAccount
     * @param resId
     * @param functionName
     * @param session
     * @return
     */
    private static boolean resFunctionValidate(String userId, Long resId, String functionName, HttpSession session) {
        if (UserUtil.getInstance().isSysAdmin(userId)) {
            return true;
        }
        if (UserUtil.getInstance().isGuest(userId)) { //guest用户有全部数据的查看权限，此处为功能权限
            return false;
        }
        return hasParentResPower(userId, resId, functionName, session);
    }

    /**
     * 根据账号，资源ID和功能名称返回该资源功能是否有权限。
     * HttpSession对象用于获取用户会话，因为用户权限在用户登录的时候存放在session会话中。
     * 
     * @param userAccount
     * @param resId
     * @param functionName
     * @param session
     * @return
     */
    private static boolean hasResPrivilege(String userId, Long resId, String functionName, HttpSession session) {
        List<Long> idlist = getResIdListForUser(userId, functionName, session);
        for (int i = 0; i < idlist.size(); i++) {
            if (resId == idlist.get(i).intValue()) {
                return true;
            }
        }
        return false;
    }

    /**
     * 向上递归查询资源点是否有权限
     * 
     * @param userAccount
     * @param resId
     * @param functionName
     * @param session
     * @return
     */
    private static boolean hasParentResPower(String userId, Long resId, String functionName, HttpSession session) {
        boolean hasPower = hasResPrivilege(userId, resId, functionName, session);
        if (hasPower) {
            return true;
        } else {
            List<ResBean> parents = RelationHelper.parents(resId);
            for (ResBean resBean : parents) {
                boolean b = hasParentResPower(userId, resBean.res().getId(), functionName, session);
                if (b) {
                    return true;
                }
            }
            return false;
        }
    }

    /**
     * 获取一个用户某个功能所有设置的资源id集合，只返回已设置的。
     * 
     * @param functionName
     * @return
     */
    public static List<Long> getResIdListForUser(String functionName) {
        String userId = UserUtil.getInstance().getCurrentUserId();
        return getResIdListForUser(userId, functionName, Struts2Utils.getRequest().getSession());
    }

    /**
     * 获取一个用户某个功能所有设置的资源id集合，非root用户用户权限在第一次获取的时候放在session会话中
     * 非系统管理员用户权限存放在http会话session中，所以需要提供session对象。
     * 如果session为空则直接从分布式缓存获取。
     * 
     * @param userAccount
     * @param operId
     * @param session 用户访问会话
     * @return
     */
    private static List<Long> getResIdListForUser(String userId, String functionName, HttpSession session) {
        List<Long> list = new ArrayList<Long>();
        if (UserUtil.getInstance().isSysAdmin(userId) || UserUtil.getInstance().isGuest(userId)) {//guest用户有全部数据的查看权限
            list.addAll(getAllTopRes());
        } else {
            List<Long> resIdList = getUserPurviewResIdList(userId, session, functionName);
            for (int i = 0; resIdList != null && i < resIdList.size(); i++) {
                Long resId = resIdList.get(i);
                if (!list.contains(resId)) {
                    list.add(resId);
                }
            }
        }
        return list;
    }

    /**
     * 获取一个用户查看topo权限的id集合
     * 
     * @return
     */
    public static List<Long> getTopoIdListForUser() {
        String userId = UserUtil.getInstance().getCurrentUserId();
        return getTopoIdListForUser(userId, Struts2Utils.getRequest().getSession());
    }

    /**
     * 获取自定义的有权限的性能图
     * 
     * @return
     */
    public static List<Long> getCustomRealTimeIdListForUser() {
        String userId = UserUtil.getInstance().getCurrentUserId();
        return getCustomRealTimeIdListForUser(userId, Struts2Utils.getRequest().getSession());
    }

    /**
     * 获取一个用户查看topo权限的id集合，非root用户用户权限在第一次获取的时候放在session会话中
     * 非系统管理员用户权限存放在http会话session中，所以需要提供session对象。
     * 如果从session中获取为空则直接从分布式缓存获取。
     * 
     * @param userId
     * @param session
     * @return
     */
    private static List<Long> getTopoIdListForUser(String userId, HttpSession session) {
        List<Long> list = new ArrayList<Long>();
        if (UserUtil.getInstance().isSysAdmin(userId) || UserUtil.getInstance().isGuest(userId)) {//guest用户有全部数据的查看权限
            list.addAll(getAllTopo());
        } else {
            List<Long> topuIdList = getUserPurviewTopuIdList(userId, session);
            for (int i = 0; topuIdList != null && i < topuIdList.size(); i++) {
                Long topuId = topuIdList.get(i);
                if (!list.contains(topuId)) {
                    list.add(topuId);
                }
            }
        }
        return list;
    }

    /**
     * 获取一个用户查看realTime(性能图)权限的id集合，非root用户用户权限在第一次获取的时候放在session会话中
     * 非系统管理员用户权限存放在http会话session中，所以需要提供session对象。
     * 如果从session中获取为空则直接从分布式缓存获取。
     * 
     * @param userId
     * @param session
     * @return
     */
    private static List<Long> getCustomRealTimeIdListForUser(String userId, HttpSession session) {
        List<Long> list = new ArrayList<Long>();
        if (UserUtil.getInstance().isSysAdmin(userId) || UserUtil.getInstance().isGuest(userId)) {//guest用户有全部数据的查看权限
            list.addAll(getAllRealTime());
        } else {
            List<Long> realTimeIdList = getUserPurviewCustomRealTimeIdList(userId, session);
            for (int i = 0; realTimeIdList != null && i < realTimeIdList.size(); i++) {
                Long realTimeId = realTimeIdList.get(i);
                if (!list.contains(realTimeId)) {
                    list.add(realTimeId);
                }
            }
        }
        return list;
    }

    /**
     * 根据账号、操作标识获取有权限资源集合。
     * 非系统管理员用户权限存放在http会话session中，所以需要提供session对象。
     * 如果从session中获取为空则直接从分布式缓存获取。
     * 
     * @param userAccount
     * @param session
     * @param operId
     * @return
     */
    private static List<Long> getUserPurviewResIdList(String userAccount, HttpSession session, String operId) {
        Map<String, Map<String, List<Long>>> map = getUserPurviewMap(userAccount, session);
        Map<String, List<Long>> temp = map.get(FunctionConstants.TYPE_RES_FUNCTION);
        return temp.get(operId);
    }

    /**
     * 根据账号、操作标识获取有权限查看topu集合。
     * 非系统管理员用户权限存放在http会话session中，所以需要提供session对象。
     * 如果从session中获取为空则直接从分布式缓存获取。 
     * 
     * @param userId
     * @param session
     * @return
     */
    private static List<Long> getUserPurviewTopuIdList(String userId, HttpSession session) {
        Map<String, Map<String, List<Long>>> map = getUserPurviewMap(userId, session);
        Map<String, List<Long>> temp = map.get(FunctionConstants.TYPE_TOPO_FUNCTION);
        return temp.get(FunctionConstants.VIEW_TOPO);
    }

    /**
     * 根据账号、操作标识获取有权限查看自定义性能图集合。
     * 非系统管理员用户权限存放在http会话session中，所以需要提供session对象。
     * 如果从session中获取为空则直接从分布式缓存获取。  
     * 
     * @param userId
     * @param session
     * @return
     */
    private static List<Long> getUserPurviewCustomRealTimeIdList(String userId, HttpSession session) {
        Map<String, Map<String, List<Long>>> map = getUserPurviewMap(userId, session);
        Map<String, List<Long>> temp = map.get(FunctionConstants.TYPE_REAL_TIME_FUNCTION);
        return temp.get(FunctionConstants.VIEW_REAL_TIME);
    }

    /**
     * 根据用户ID获取对象权限集合
     * 
     * @param userId
     * @return
     */
    public static List<ObjFunRel> getObjFunRel(String userId) {
        List<ObjFunRel> objFunRels = null;
        objFunRels = UAMFascade.getUserInfoFactory().findObjFunRels(userId, SystemContext.getProperty(FunctionConstants.SYSTEM_ID_KEY).toString());
        if (objFunRels == null) {
            objFunRels = new ArrayList<ObjFunRel>();
        }
        return objFunRels;
    }

    /**
     * 私有方法，根据账号从session中获取权限数据，如果没有则创建一个放入session中。
     * 用户的权限数据格式为map集合 key值为分类标识，内部Map的key值为操作标识 值为list集合，list集合中为id集合。
     * session为http会话session,重新访问失效. 如果session为空则直接从分布式缓存中获取。
     * 
     * @param userAccount
     * @param session
     * @return
     */
    private static Map<String, Map<String, List<Long>>> getUserPurviewMap(String userId, HttpSession session) {
        Object obj = null;
        if (session != null) {
            obj = session.getAttribute(userId + UserUtil.PURVIEW);
        }
        if (obj == null) {
            Map<String, Map<String, List<Long>>> userMap = new HashMap<String, Map<String, List<Long>>>();
            Map<String, List<Long>> systemMap = new HashMap<String, List<Long>>();
            Map<String, List<Long>> resMap = new HashMap<String, List<Long>>();
            Map<String, List<Long>> topoMap = new HashMap<String, List<Long>>();
            Map<String, List<Long>> viewMap = new HashMap<String, List<Long>>();
            Map<String, List<Long>> realTimeMap = new HashMap<String, List<Long>>();
            List<ObjFunRel> list = getObjFunRel(userId);
            for (int i = 0; i < list.size(); i++) {
                ObjFunRel objFunRel = list.get(i);
                String funId = objFunRel.getFunId();
                String objId = objFunRel.getObjId();
                if (FunctionConstants.VIEW_REPORT.equals(funId) || FunctionConstants.TOPO_MANAGER.equals(funId) || FunctionConstants.STRATEGY_MANAGER.equals(funId) || FunctionConstants.SYSTEM_MANAGER.equals(funId)) {
                    List<Long> temp = new ArrayList<Long>();
                    temp.add(1L);//有值即为真
                    systemMap.put(funId, temp);
                } else if (FunctionConstants.VIEW_RES.equals(funId) || FunctionConstants.EDIT_RES.equals(funId) || FunctionConstants.HANDLE_EVENT.equals(funId)) {
                    //如果为资源ID则直接放，视图ID获取全部该视图下根节点资源
                    List<Long> resList = resMap.get(funId);
                    if (resList == null) {
                        resList = new ArrayList<Long>();
                    }
                    //                    视图是否可以新增资源
                    String[] objIds = objId.split("_");
                    if (objIds[1].equalsIgnoreCase("V")) {
                        List<Long> vieResList = viewMap.get(FunctionConstants.VIEW_ADD_RES);
                        if (vieResList == null) {
                            vieResList = new ArrayList<Long>();
                        }
                        buildViewIdList(vieResList, objId);
                        viewMap.put(FunctionConstants.VIEW_ADD_RES, vieResList);
                    }
                    //                    end  视图是否可以新增资源
                    buildResIdList(resList, objId);
                    resMap.put(funId, resList);
                } else if (FunctionConstants.VIEW_TOPO.equals(funId)) {
                    //如果为topo ID则直接放，如果为目录获取该目录及子目录下所有拓扑节点
                    //如果为topo 根授权点，则放全部
                    List<Long> topoList = topoMap.get(funId);
                    if (topoList == null) {
                        topoList = new ArrayList<Long>();
                    }
                    buildTopoIdList(topoList, objId);
                    topoMap.put(funId, topoList);
                } else if (FunctionConstants.VIEW_VIEW.equals(funId)) {
                    List<Long> viewList = viewMap.get(funId);
                    if (viewList == null) {
                        viewList = new ArrayList<Long>();
                    }
                    buildViewIdList(viewList, objId);
                    viewMap.put(funId, viewList);
                } else if (FunctionConstants.VIEW_REAL_TIME.equals(funId)) {
                    List<Long> realTimeList = realTimeMap.get(funId);
                    if (realTimeList == null) {
                        realTimeList = new ArrayList<Long>();
                    }
                    buildRealTimeIdList(realTimeList, objId);
                    realTimeMap.put(funId, realTimeList);
                }
            }
            userMap.put(FunctionConstants.TYPE_SYSTEM_FUNCTION, systemMap);
            userMap.put(FunctionConstants.TYPE_RES_FUNCTION, resMap);
            userMap.put(FunctionConstants.TYPE_TOPO_FUNCTION, topoMap);
            userMap.put(FunctionConstants.TYPE_VIEW_FUNCTION, viewMap);
            userMap.put(FunctionConstants.TYPE_REAL_TIME_FUNCTION, realTimeMap);
            obj = userMap;
            if (session != null) {
                session.setAttribute(userId + UserUtil.PURVIEW, userMap);
            }
        }
        return (Map) obj;
    }

    /**
     * 构建视图节点
     * 
     * @param viewList
     * @param objId
     */
    private static void buildViewIdList(List<Long> viewList, String objId) {
        String[] objIds = objId.split("_");
        if (objIds[1].equalsIgnoreCase("V")) {
            viewList.add(Long.valueOf(objIds[2]));
        }
    }

    /**
     * 构建有权限的资源ID，不排重
     * 
     * @param resMap
     * @param objId
     */
    private static void buildResIdList(List<Long> resList, String objId) {
        String[] objIds = objId.split("_");
        if (objIds[1].equalsIgnoreCase("V")) {
            resList.addAll(getTopRes(Long.valueOf(objIds[2])));
        } else if (objIds[1].equalsIgnoreCase("R")) {
            resList.add(Long.valueOf(objIds[2]));
        }
    }

    /**
     * 构建有权限的TOPO ID，不排重
     * 
     * @param list
     * @param objId
     */
    private static void buildTopoIdList(List<Long> list, String objId) {
        if ("BSM_TOPO".equals(objId)) {//全部，直接放入全部返回
            list.addAll(getAllTopo());
        } else {
            String[] objIds = objId.split("_");
            if (objIds != null && objIds.length == 3) {
                if (objIds[1].equalsIgnoreCase("C")) {
                    list.addAll(getTopoByCatalog(Long.valueOf(objIds[2])));
                } else if (objIds[1].equalsIgnoreCase("T")) {
                    list.add(Long.valueOf(objIds[2]));
                }
            }
        }
    }

    /**
     * 构建有权限的RealTime ID，不排重
     * 
     * @param list
     * @param objId
     */
    private static void buildRealTimeIdList(List<Long> list, String objId) {
        if ("BSM_X_REALTIME".equals(objId)) {
            list.addAll(getAllRealTime());
        } else {
            String[] objIds = objId.split("_");
            if (objIds != null && objIds.length == 3) {
                list.add(Long.valueOf(objIds[2]));
            }
        }
    }

    /**
     * 获取各个视图下全部顶级资源节点ID集合
     * 
     * @return
     */
    private static List<Long> getAllTopRes() {
        List<Long> resIdList = new ArrayList<Long>();
        ResView[] resViews = resViewCache.findAll();
        if (resViews != null) {
            for (int i = 0; i < resViews.length; i++) {
                if (resViews[i].getId() == 1L) {
                    //应用视图
                    List<Res> appList = resCache.getByResType(1105050000000L);
                    for (Res app : appList) {
                        resIdList.add(app.getId());
                    }
                    continue;
                } else if (resViews[i].getId() == 2L) {
                    //基础视图
                    continue;
                }
                List<ResViewRel> relList = resViewRelCache.getResViewRelByViewId(resViews[i].getId());
                if (relList != null) {
                    for (ResViewRel resViewRel : relList) {
                        if (resCache.get(resViewRel.getResId()) != null) {
                            resIdList.add(resViewRel.getResId());
                        }
                    }
                }
            }
        }
        return resIdList;
    }

    /**
     * 获取某视图的全部顶级资源ID
     * 
     * @param resViewId
     * @return
     */
    private static List<Long> getTopRes(Long resViewId) {
        List<Long> resIdList = new ArrayList<Long>();
        if (resViewId == 1L) {
            //应用视图
            List<Res> appList = resCache.getByResType(1105050000000L);
            for (Res app : appList) {
                resIdList.add(app.getId());
            }

        } else {
            List<ResViewRel> relList = resViewRelCache.getResViewRelByViewId(resViewId);
            if (relList != null) {
                for (ResViewRel resViewRel : relList) {
                    if (resCache.get(resViewRel.getResId()) != null) {
                        resIdList.add(resViewRel.getResId());
                    }
                }
            }
        }
        return resIdList;
    }

    /**
     * 获取全部的topo节点
     * 
     * @return
     */
    private static List<Long> getAllTopo() {
        List<Long> list = new ArrayList<Long>();
        List<TopuConf> temp = topuConfCache.findAll();
        if (temp != null) {
            for (TopuConf topuConf : temp) {
                list.add(topuConf.getId());
            }
        }
        return list;
    }

    /**
     * 获取全部自定义性能图节点
     * 
     * @return
     */
    private static List<Long> getAllRealTime() {
        List<Long> list = new ArrayList<Long>();
        List<RealTimeViewConf> realTimeViewConfList = SpringContextHolder.getBean(RealTimeService.class).findAllFreeCustomView();
        if (realTimeViewConfList != null) {
            for (RealTimeViewConf realTimeViewConf : realTimeViewConfList) {
                list.add(realTimeViewConf.getId());
            }
        }
        return list;
    }

    /**
     * 根据目录获取topo节点 
     * 
     * @param catalogId
     * @return
     */
    private static List<Long> getTopoByCatalog(Long catalogId) {
        List<Long> result = new ArrayList<Long>();
        List<TopuCatalog> list = topuCatalogCache.findChildren(catalogId);
        for (TopuCatalog topuCatalog : list) {
            List<TopuConf> topuConfList = topuConfCache.findByCatalogId(topuCatalog.getId());
            if (topuConfList != null) {
                for (TopuConf topuConf : topuConfList) {
                    result.add(topuConf.getId());
                }
            }
        }
        return result;
    }

}
